<template>
  <div style="height: 100%">
    <div class="calendar-container">
      <div class="calendar-top">
        <slot name="calendarTop" />
      </div>
      <div class="calendar-title-row">
        <div class="left">
          <div class="left-icon" @click="globalClick('left')">
             <img :tabindex="0" :src="backActive ? backActImg : backImg" @focus="backActive = true" @blur="backActive = false" alt="Image" style="width: 1.5vh; height: 1.5vh;"/>
          </div>
          <div class="timeTitle" @click="globalClick('timeTitle')">{{ timeTitle }}</div>
          <div class="right-icon" @click="globalClick('right')">
            <img :tabindex="0" :src="nextActive ? nextActImg : nextImg" @focus="nextActive = true" @blur="nextActive = false" alt="Image" style="width: 1.5vh; height: 1.5vh;"/>
          </div>
        </div>
        <div class="right">
          <div
            v-for="(item, index) in mergedCustomIcons"
            :key="index"
            class="custom-icon"
            @click="item.action ? item.action(item.attrs, $event, item) : globalClick(item.attrs, $event, item)"
          >
            <i :class="item.iconClass" :title="item.tooltip"></i>
          </div>
        </div>
      </div>
      <div class="calendar-content" v-show="showRules.showCalendar">
        <div class="day" v-if="timeType == 'day'">
          <div class="day-header">
            <div class="day-header-item" v-for="item in tableData" :key="item">
              {{ item }}
            </div>
          </div>
          <div class="day-content">
            <div
              @mouseenter="handleMouseEnter($event, 'day', item)"
              @mouseleave="handleMouseLeave($event, 'day', item)"
              :class="{'day-content-item' : true, afterToday : isAfterToday(item)}"
              v-for="(item, index) in dateData"
              :key="index"
              @click="globalClick('dayClick', item)"
            >
              <div style="display: flex; align-items: center">
                <template v-if="isAddition(item)"></template>
                <template v-else-if="isToday(item)" >
                  <div class="today">{{ item }}</div>
                  <div class="today_name">今天</div>
                </template>
                <div v-else class="day-title">
                  {{ item }}
                </div>
              </div>
              <div class="day-number" v-if="isAddition(item)"></div>
              <div class="day-number" v-else-if="item">
                <slot
                  name="dayGridContent"
                  :dayData="dayData[index - prefixEmptyDays]"
                  :valueIndex="index - prefixEmptyDays"
                ></slot>
              </div>
              <span class="day-number" v-else>
                <slot name="dayGridNoContent"></slot>
              </span>
            </div>
          </div>
        </div>
        <div class="month" v-else-if="timeType == 'month'">
          <div class="month-content">
            <div
              class="month-content-item"
              @mouseenter="handleMouseEnter($event, 'month', item)"
              @mouseleave="handleMouseLeave($event, 'month', item)"
              v-for="item in 12"
              :key="item"
              @click="globalClick('monthClick', item)"
            >
              <div style="display: flex; align-items: center; margin: 10px">
                <span :class="{ 'month-title': true, toMonth: isToMonth(item) }">
                  <span>{{ item + "月" }}</span>
                </span>
              </div>
              <span class="month-number" v-if="item">
                <slot name="monthGridContent" :monthData="monthData[item - 1]" :valueIndex="item - 1"></slot>
              </span>
              <span class="month-number" v-else>
                <slot name="monthGridNoContent"></slot>
              </span>
            </div>
          </div>
        </div>
        <div class="years" v-else-if="timeType == 'years'">
          <div class="years-table">
            <div
              :class="['years-table-item', isYearOutOfRange(index) ? 'years-table-item-disable' : '']"
              v-for="(item, index) in 12"
              :key="item"
              @mouseenter="isYearOutOfRange(index) ? '' : handleMouseEnter($event, 'years', item)"
              @mouseleave="isYearOutOfRange(index) ? '' : handleMouseLeave($event, 'years', item)"
              @click="globalClick('yearClick', titleYear - 11 + index)"
            >
              <div style="display: flex; align-items: center; margin: 10px">
                <span :class="{ 'years-title': true, toYear: isToYear(titleYear - yearGap + index) }">
                  <span>{{ titleYear - yearGap + index }}</span>
                </span>
              </div>
              <span class="years-number" v-if="item">
                <slot name="yearGridContent" :yearData="yearData[item - 1]" :valueIndex="item - 1"></slot>
              </span>
              <span class="years-number" v-else>
                <slot name="yearGridNoContent"></slot>
              </span>
            </div>
          </div>
        </div>
      </div>
      <slot name="customContent"></slot>
    </div>
  </div>
</template>

<script>
import backImg from "@/assets/image/back.png";
import backActImg from "@/assets/image/back_focus.png";
import nextImg from "@/assets/image/next.png";
import nextActImg from "@/assets/image/next_focus.png";
export default {
  props: {
    // 一月每日
    dayData: {
      type: Array,
      default: () => [],
    },
    // 一年每月
    monthData: {
      type: Array,
      default: () => [],
    },
    // 年
    yearData: {
      type: Array,
      default: () => [],
    },
    customIcons: {
      type: Array,
      default: () => [],
    },
    showDefaultIcons: {
      type: Boolean,
      default: false,
    },
    yearGap: {
      type: Number,
      default: 11,
    },
    chartTitle: {
      type: Object,
      default: () => ({
        day: "本月统计情况",
        month: "本年统计情况",
        years: "近十二年统计情况",
      }),
    },
    customStrategy: {
      type: Object,
      default: () => {},
    },
    customRule: {
      type: Object,
      default: () => {},
    },
  },
  data() {
    return {
      calendarTitleRowOptions: {},
      titleYear: new Date().getFullYear(),
      titleMonth: new Date().getMonth(),
      minYears: this.getMinYear(),
      maxYears: this.getMaxYear(),
      tableData: ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"],
      timeType: "day",
      prefixEmptyDays: 0,
      timeTitle: "",
      defaultRightIcons: [
        {
          action: this.refresh,
          iconClass: "el-icon-refresh-right",
          attrs: {
            type: "refresh",
            showRule: "showCalendar",
          },
          tooltip: "回到当月",
        },
        {
          action: this.reDate,
          iconClass: "el-icon-date",
          attrs: {
            type: "reDate",
            showRule: "showCalendar",
          },
          tooltip: "日历",
        },
      ],
      showRule: {
        showCalendar: true,
      },
      globalClickSelector: {
        day: this.defaultDayStrategy,
        month: this.defaultMonthStrategy,
        years: this.defaultYearStrategy,
        timeTitle: this.defaultTitleStrategy,
        ...this.customStrategy,
      },
      backActive: false,
      nextActive: false,
      backImg:backImg,
      nextImg:nextImg,
      backActImg:backActImg,
      nextActImg:nextActImg,
    };
  },
  created() {
    // 显示标题
    this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
    // 计算日期
    this.getDays(this.titleYear, this.titleMonth);
  },
  computed: {
    showRules() {
      return { ...this.showRule, ...this.customRule };
    },
    mergedCustomIcons() {
      if (this.showDefaultIcons) {
        return [...this.defaultRightIcons, ...this.customIcons];
      } else {
        return this.customIcons;
      }
    },
    isAfterToday() {
      return (dayNumber) => {
      const givenDate = new Date(this.titleYear, this.titleMonth, parseInt(dayNumber));
      const today = new Date();
      // 比较两个日期
      // 注意：Date对象可以直接进行比较，JavaScript会自动将它们转换为时间戳
      return givenDate > today;
      };
    },
    isToday() {
      return (dayNumber) => {
        const today = new Date();
        const dd = today.getDate();
        const mm = today.getMonth() + 1;
        const yyyy = today.getFullYear();

        return this.titleYear === yyyy && this.titleMonth + 1 === mm && parseInt(dayNumber) === dd;
      };
    },
    isToMonth() {
      return (monthNumber) => {
        const today = new Date();
        const mm = today.getMonth() + 1;
        const yyyy = today.getFullYear();

        return this.titleYear === yyyy && mm === monthNumber;
      };
    },
    isToYear() {
      return (yearNumber) => {
        const today = new Date();
        const yyyy = today.getFullYear();

        return yearNumber === yyyy;
      };
    },
  },
  watch: {
    timeTitle() {
      this.updatingTimeData();
    },
  },
  methods: {
    isAddition(date){
      if(date === 'left' || date === 'right') return true;
    },
    reset() {
      for (let key in this.customRule) {
        this.customRule[key] = false;
      }
      for (let key in this.showRule) {
        this.showRule[key] = false;
      }
    },
    reload() {
      const trueKeys = Object.keys(this.showRules).filter((key) => this.showRules[key] === true);
      for (const key of trueKeys) {
        if (key in this.globalClickSelector) {
          this.globalClickSelector[key]();
        }
      }
    },
    refresh(attrs) {
      const { showRule } = attrs;
      this.reset();
      this.showRule[showRule] = true;
      this.titleYear = new Date().getFullYear();
      this.titleMonth = new Date().getMonth();
      this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
      // 计算日期
      this.getDays(this.titleYear, this.titleMonth);
    },
    reDate(attrs) {
      const { showRule } = attrs;
      this.reset();
      this.showRule[showRule] = true;
    },
    // 鼠标进入或离开事件处理函数
    handleMouseEnterOrLeave($event, type, item) {
      if (!this.isYearOutOfRange(item)) {
        this.handleMouseEnter($event, type, item);
      }
    },
    isYearOutOfRange(index) {
      const year = this.titleYear - this.yearGap + index;
      return year < this.minYears || year > this.maxYears;
    },
    getMinYear() {
      return new Date().getFullYear() - this.yearGap;
    },
    getMaxYear() {
      return new Date().getFullYear() + this.yearGap;
    },
    updatingTimeData() {
      this.$emit("updatingTimeData", {
        years: this.titleYear,
        month: this.titleMonth + 1,
        type: this.timeType,
      });
    },
    defaultTitleStrategy() {
      if (this.timeType == "day") {
        this.timeType = "month";
        this.timeTitle = this.titleYear;
      } else if (this.timeType == "month") {
        this.timeType = "years";
        this.timeTitle = `${this.titleYear - 11}-${this.titleYear}`;
      } else if (this.timeType == "years") {
        this.timeType = "day";
        this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
        this.getDays(this.titleYear, this.titleMonth);
      }
    },
    defaultDayStrategy(clickAttr, options) {
      const actions = {
        left: () => {
          if (this.titleMonth - 1 < 0) {
            if (this.titleYear - 1 <= this.minYears) {
              this.$message.warning(`年份不能小于最小年份${this.minYears}`);
              return;
            }
            this.titleMonth = 11;
            this.titleYear = this.titleYear - 1;
          } else {
            this.titleMonth = this.titleMonth - 1;
          }
          this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
          this.getDays(this.titleYear, this.titleMonth);
        },
        right: () => {
          this.titleMonth = this.titleMonth + 1;
          if (this.titleMonth > 11) {
            this.titleMonth = 0;
            this.titleYear = this.titleYear + 1;
          }
          if (this.titleYear > this.maxYears) {
            this.titleMonth = 12;
            this.titleYear = this.titleYear - 1;
            this.$message.warning(`年份不能大于最大年份${this.maxYears}`);
            return;
          }
          this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
          this.getDays(this.titleYear, this.titleMonth);
        },
        dayClick: (options) => {
          if (options) {
            this.$emit(
              "clickDays",
              `${this.titleYear}-${
                this.titleMonth + 1 < 10 ? `0${this.titleMonth + 1}` : this.titleMonth + 1
              }-${options}`
            );
          }
        },
      };
      const action = actions[clickAttr];
      if (action) {
        action(options);
      }
    },
    defaultMonthStrategy(clickAttr, options) {
      const actions = {
        left: () => {
          if (this.titleYear <= this.minYears) {
            this.$message.warning(`年份不能小于最小年份${this.minYears}`);
            return;
          }
          this.titleYear = this.titleYear - 1;
          this.timeTitle = this.titleYear;
        },
        right: () => {
          if (this.titleYear >= this.maxYears) {
            this.$message.warning(`年份不能大于最大年份${this.maxYears}`);
            return;
          }
          this.titleYear = this.titleYear + 1;
          this.timeTitle = this.titleYear;
        },
        monthClick: (options) => {
          if (options) {
            this.titleMonth = options - 1;
            this.timeType = "day";
            this.timeTitle = `${this.titleYear}年${this.titleMonth + 1}月`;
            this.getDays(this.titleYear, this.titleMonth);
            this.$emit("monthClick", {
              years: this.titleYear,
              month: this.titleMonth,
            });
          }
        },
      };

      const action = actions[clickAttr];
      if (action) {
        action(options);
      }
    },
    defaultYearStrategy(clickAttr, options) {
      const actions = {
        left: () => {
          if (this.titleYear - 11 <= this.minYears) {
            this.$message.warning(`年份不能小于最小年份${this.minYears}`);
            return;
          }
          this.titleYear = this.titleYear - 11;
          this.timeTitle = `${this.titleYear - 11}-${this.titleYear}`;
        },
        right: () => {
          if (this.titleYear >= this.maxYears) {
            this.$message.warning(`年份不能大于最大年份${this.maxYears}`);
            return;
          }
          this.titleYear = this.titleYear + 11;
          this.timeTitle = `${this.titleYear - 11}-${this.titleYear}`;
        },
        yearClick: (options) => {
          const option = options[0];
          if (option && option >= this.minYears && option <= this.maxYears) {
            this.titleYear = option;
            this.timeType = "month";
            this.timeTitle = this.titleYear;
          }
          this.$emit("monthClick", {
            years: this.titleYear,
            month: this.titleMonth,
          });
        },
      };

      const action = actions[clickAttr];
      if (action) {
        action(options);
      }
    },
    globalClick(clickAttr, ...options) {
      let strategy;

      if (clickAttr in this.globalClickSelector) {
        strategy = this.globalClickSelector[clickAttr];
      } else {
        strategy = this.globalClickSelector[this.timeType];
      }
      if (strategy) {
        strategy(clickAttr, options);
      }
    },
    handleMouseEnter(e, type, data) {
      if (!data) {
        return;
      }
      e.target.classList.add(`${type}-table-item-handleMouseEnter`);
    },
    // 鼠标移出去事件
    handleMouseLeave(e, type, data) {
      if (!data) {
        return;
      }
      e.target.classList.remove(`${type}-table-item-handleMouseEnter`);
    },
    // 计算星期几
    getWeek(date) {
      const week = [0, 1, 2, 3, 4, 5, 6];
      return week[date.getDay()];
    },
    // 计算天数
    getDays() {
      this.dateData = [];
      const week = this.getWeek(new Date(this.titleYear, this.titleMonth, 1));
      const daysInMonth = new Date(this.titleYear, this.titleMonth + 1, 0).getDate();
      this.prefixEmptyDays = week > 0 ? week - 1 : 6;

      for (let i = 0; i < this.prefixEmptyDays; i++) {
        this.dateData.push("left");
      }

      for (let day = 1; day <= daysInMonth; day++) {
        // 使用 padStart 将日期补零到两位数
        this.dateData.push(String(day).padStart(2, "0"));
      }

      // 补足月末不足的空字符串
      if (this.dateData.length % 7 !== 0) {
        const remainingDays = 7 - (this.dateData.length % 7);
        for (let i = 0; i < remainingDays; i++) {
          this.dateData.push("right");
        }
      }
    },
  },
};
</script>

<style lang="scss" scoped>
.calendar-container {
  position: relative;
  background-color: #ffffff;
  width: 100%;
  height: 100%;
  overflow: auto;
  .calendar-top {
    position: sticky;
  }
  .chart-container {
    position: absolute;
    height: 60%;
    width: 80%;
    top: 20%;
    left: 10%;
    background-color: pink;
  }
  .calendar-title-row {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin: 8px;
    .left {
      display: flex;
      align-items: center;
      .left-icon {
        font-size: 20px;
        font-weight: 1000;
        cursor: pointer;
      }
      .timeTitle {
        font-size: 16px;
        margin: 0 16px;
        font-weight: 1000;
        cursor: pointer;
      }
      .right-icon {
        font-size: 20px;
        font-weight: 1000;
        cursor: pointer;
      }
    }

    .right {
      display: flex;
      align-items: center;
      .custom-icon {
        font-size: 20px;
        font-weight: 1000;
        margin-left: 24px;
        cursor: pointer;
      }
    }
  }

  .calendar-content {
    margin: 8px;
    height: 700px;

    .afterToday {
      background-color: #ffffff;
      opacity: 0.4;
    }

    .day {
      .day-header {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        flex-wrap: wrap;
        background-color: #fbfbfb;
        .day-header-item {
          width: calc(100% / 7);
          height: 40px;
          line-height:40px;
          font-size: 16px;
          font-weight: 1000;
          padding-left: 20px;
          box-sizing: border-box;
          border: 1px solid #ecf0fc;
          border-right: none;
        }
        .day-header-item:last-child{
          border-right: 1px solid #ecf0fc;
        }
      }
      .day-content {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        flex-wrap: wrap;
        .day-content-item {
          width: calc(100% / 7);
          height: 110px;
          display: flex;
          align-items: flex-start;
          flex-direction: column;
          padding: 5px 20px 5px 20px;
          text-align: center;
          border: 0.5px solid #ecf0fc;
          border-top: none;
          box-sizing: border-box;
          .day-title {
            display: inline-block;
            font-weight: 1000;
            font-size: 16px;
            text-align: left;
            padding: 2px;
          }
          .today {
            font-weight: 1000;
            font-size: 16px;
            width: 26px;
            height: 26px;
            line-height: 26px;
            border-radius: 13px;
            color: #ffffff;
            text-align: center;
            padding: 0 2px 0 0;
            background-color: #436de5;
          }
          .today_name {
            margin-left: 10px;
            font-weight: 600;
            line-height: 20px;
            font-size: 14px;
            color:#436de5;
          }
          .day-number {
            width: 100%;
            font-size: 14px;
            align-content: center;
            height: 75px;
            overflow: auto;
            scrollbar-width: none; /* 针对Firefox */
            -ms-overflow-style: none
          }
        }

        .day-table-item-handleMouseEnter {
          transition: transform 0.3s ease;
          // 选中阴影效果
          // box-shadow: 0px 0px 4px rgba(0, 0, 0, 0.3); /* 阴影效果 */
          // border: none;
          // box-sizing: border-box;
          // 选中背景颜色效果
          border: 2px solid #436de5;
          cursor: pointer;
        }
        .day-content-item:active{
          background-color: #eef6ff;
        }
      }
    }

    .month {
      .month-content {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        flex-wrap: wrap;
        .month-content-item {
          width: calc(100% / 4);
          height: auto;
          min-height: 20vh;
          max-height: 24vh;
          padding: 10px;
          text-align: center;
          display: flex;
          align-items: flex-start;
          flex-wrap: wrap;
          box-sizing: border-box;
          border: 8px solid #ecf0fc;
          .month-title {
            display: inline-block;
            font-weight: 1000;
            font-size: 20px;
            text-align: left;
            margin: 5px 10px 0 10px;
          }
          .toMonth {
            width: 50px;
            height: 30px;
            line-height: 30px;
            border-radius: 50%;
            color: #ffffff;
            text-align: center;
            background-color: #436de5;
          }
          .month-number {
            width: 100%;
            font-size: 16px;
            height: auto;
            min-height: 150px;
          }
        }
        .month-table-item-handleMouseEnter {
          transition: transform 0.3s ease;
          border: 2px solid #436de5;
          cursor: pointer;
        }
        .month-content-item:active{
          background-color: #eef6ff;
        }
      }
    }
    .years {
      .years-table {
        display: flex;
        justify-content: flex-start;
        align-items: center;
        flex-wrap: wrap;
        .years-table-item {
          width: calc(100% / 4);
          height: auto;
          min-height: 20vh;
          max-height: 24vh;
          padding: 10px;
          text-align: center;
          display: flex;
          align-items: flex-start;
          flex-wrap: wrap;
          box-sizing: border-box;
          border: 8px solid #ecf0fc;
          .years-title {
            display: inline-block;
            font-weight: 1000;
            font-size: 20px;
            text-align: left;
            padding: 10px 20px 10px 20px;
          }
          .years-number {
            width: 100%;
            font-size: 16px;
            height: auto;
            min-height: 150px;
          }
          .toYear {
            position: relative;
            display: inline-block;
            width: 50px;
            height: 26px;
            line-height: 26px;
            border-radius: 40%;
            color: #436de5;
            text-align: center;
            background-color: #EAF4FC;
          }
        }

        .years-table-item-disable {
          color: #8a8686;
        }
        .years-table-item-handleMouseEnter {
          transition: transform 0.3s ease;
          border: 2px solid #436de5;
          cursor: pointer;
        }
        .years-table-item:active{
          background-color: #eef6ff;
        }
      }
    }
  }
}
</style>
